﻿(function(window){
var 
	mooluBM = function(){
		return new muBM(Array.prototype
						  .slice.apply(arguments));
	},
	
	muBM = function(arryConfig){
		this._init(arryConfig);
		this._initContainer();
		this._initNodes();
		this.reset(this.options.defaultIndex);
	};

muBM.prototype = {
	
	_init : function(params){
		var 
			cfg = {},
			len = params.length,
			p, param;
			
		for(var i=2; i<len; i++){
		    
			param = params[i];
			switch(typeof param){
				
				case 'number':
					
					break;
				case 'string':
					
					break;
				case 'function':
				
					break;
				case 'object':
					
					for(p in param){
						cfg[p] = param[p];
					}
			}
		}
		
		var container = this._container = params[0];
		
		this._timerDelay = null;
		this._timerMove = null;
		this._time = 0;
		this._index = 0;
		
		var opt = this._setOptions(params[1]);
		
		this.interval = opt.interval | 0;
		this.delay = opt.delay | 0;
		this.duration = opt.duration | 0;
		this.tween = opt.tween;
		this.autoClose = !!opt.autoClose;
		this.onShow = opt.onShow;
		this.onClose = opt.onClose;
		
		//set param
		var pos = this._pos = /^(bottom|top|right|left)$/.test(opt.mode.toLowerCase()) ? RegExp.$1 : 'left';
		this._horizontal = /right|left/.test(this._pos);
		this._reverse = /bottom|right/.test(this._pos);
		
		//get slide elements
		var nodes = opt.nodes ? $$A.map(opt.nodes, function(n){return n;})
			: $$OBEA.filter(container.childNodes, function(n){return n.nodeType == 1;});
		
		//create slide element collection
		this._nodes = $$OBEA.map(nodes, function(node){
			var style = node.style;
			return{	'node':node, 
					'style':style[pos], 
					'position':style.position,
					'zIndex':style.zIndex};
		});
		
		this._MOVE = $$OBEA.bind(this._move, this);
		
		var CLOSE = $$OBEA.bind(this.close, this);
		this._LEAVE = $$OBEA.bind(function(){
			clearTimeout(this._timerDelay);
			$$OBEA.selfe.fireEvent(this, 'leave');
			if(this.autoClose){
				this._timerDelay = setTimeout(CLOSE, this.delay);
			}
		}, this);
		
		$$OBEA.selfe.fireEvent(this, 'init');
	},
	
	_setOptions: function(options){
		this.options = {
			nodes: null,
			mode: 'left',
			max: 0,
			min: 0,
			delay: 100,
			interval: 20,
			duration: 20,
			defaultIndex: null,
			autoClose: true,
			tween: function(t,b,c,d){ return -c * ((t=t/d-1)*t*t*t - 1) + b; },
			onShow: function(index){},
			onClose: function(){}
		};
		return $$OBEA.extend(this.options, options || {});
	},
	
	_initContainer: function(){
		var container = this._container,
			style = container.style,
			position = $$OBEA.getStyle(container, 'position');
		
		//backup style		
		this._style = {
			'position':style.position,
			'overflow':style.overflow
		};
		
		if(position != 'relative' && position != 'absolute'){
			style.position = 'relative';
		}
		
		style.overflow = 'hidden';
		
		$$OBEA.helpe.addEvent(container, 'mouseleave', this._LEAVE);
		
		var zIndex = 100,
			gradient = this._reverse ? -1 : 1;
		
		this._each(function(o){
			var style = o.node.style;
			style.position = 'absolute';
			style.zIndex = zIndex += gradient;
		});

		$$OBEA.selfe.fireEvent(this, 'initContainer');		
	},
	
	//set slide object
	_initNodes: function(){
		var len = this._nodes.length,
			maxIndex = len - 1,
			type = this._horizontal ? 'Width' : 'Height',
			offset = 'offset' + type,
			clientSize = this._container['client' + type],
			defaultSize = Math.round(clientSize / len),
			
			//calculate default target value
			getDefaultTarget = this._reverse
				? function(i){return defaultSize * (maxIndex - i);}
				: function(i){return defaultSize * i;},
			
			max = this.options.max,
			min = this.options.min,
			getMax, getMin;
			
		//set param function
		if(max > 0 || min > 0){
			if(max > 0){
				max = Math.max(max <= 1 ? max * clientSize : Math.min(max, clientSize), defaultSize);
				min = (clientSize - max) / maxIndex;
			}else{
				min = Math.min(min < 1 ? min * clientSize : min, defaultSize);
				max = clientSize - maxIndex * min;
			}
			getMax = function(){return max;};
			getMin = function(){return min;};
		}else{
			getMax = function(o){return Math.max(Math.min(o.node[offset], clientSize), defaultSize); };
			getMin = function(o){return (clientSize - o.max) / maxIndex; };
		}
		
		this._each(function(o, i){
			
			var node = o.node,
				SHOW = $$OBEA.bind(this.show, this, i);
			
			o.SHOW =$$OBEA.bind(function(){
				clearTimeout(this._timerDelay);
				this._timerDelay = setTimeout(SHOW, this.delay);
				$$OBEA.selfe.fireEvent(this, 'enter', i);
			}, this);

			$$OBEA.helpe.addEvent(node, 'mouseenter', o.SHOW);
			
			o.current = o.defaultTarget = getDefaultTarget(i);
			o.max = getMax(o);
			o.min = getMin(o);
		});
		
		$$OBEA.selfe.fireEvent(this, 'initNodes');
	},
	
	//move
	_move: function(){
		if(this._time < this.duration){
			this._tweenMove();
			this._time++;
			this._timerMove = setTimeout(this._MOVE, this.interval);
		}else{
			this._targetMove();
			$$OBEA.selfe.fireEvent(this, 'finish');
		}
	},
	
	//tween move
	_tweenMove: function(){
		this._setPos(function(o){
			return this.tween(this._time, o.begin, o.change, this.duration);
		});
		$$OBEA.selfe.fireEvent(this, 'tweenMove');
	},
	
	//target value function
	_targetMove: function(){
		this._setPos(function(o){
			return o.target;
		});
		$$OBEA.selfe.fireEvent(this, 'targetMove');
	},
	
	//slide programs
	_easeMove: function(){
		this._time = 0;
		this._move();
	},
	
	//set coordinates values
	_setPos: function(method){
		clearTimeout(this._timerMove);
		var pos = this._pos;
		this._each(function(o, i){
			o.node.style[pos] = (o.current = Math.round(method.call(this, o))) + 'px';
		});
	},
	
	//traverse the slide object collection
	_each: function(callback){
		$$OBEA.forEach(this._nodes, callback, this);
	},
	
	//set slided param
	_setMove: function(index){
		var getTarget;
		
		if(index == undefined){//set default target
			getTarget = function(o){
				return o.defaultTarget;
			}
		}else{//set slide target by index
			var nodes = this._nodes,
				maxIndex = nodes.length - 1;
			//set index	
			this._index = index = index < 0 || index > maxIndex ?
				0 : index | 0;
			//set show param
			var nodeShow = nodes[index],
				min = nodeShow.min,
				max = nodeShow.max;
				
			getTarget = function(o, i){
				return i <= index ? min * i : min * (i-1) + max;
			};
			
			if(this._reverse){
				var get = getTarget;
				index = maxIndex - index;
				getTarget = function(o, i){
					return get(o, maxIndex - i);
				}
			}
		}
		
		this._each(function(o, i){
			o.target = getTarget(o, i); //set target value
			o.begin = o.current; //set start value
			o.change = o.target - o.begin; //set changed value
		});
		
		$$OBEA.selfe.fireEvent(this, 'setMove', index);
	},
	
	//default value moved function
	_defaultMove: function(){
		this._setPos(function(o){
			return o.defaultTarget;
		});
		$$OBEA.selfe.fireEvent(this, 'defaultMove');
	},
	
	//
	show: function(index){
		this._setMove(index | 0);
		this.onShow(this._index);
		this._easeMove();
	},
	
	//default status
	close: function(){
		this._setMove();
		this.onClose();
		this._easeMove();
	},
	
	reset : function(index){
		clearTimeout(this._timerDelay);
		if(index == undefined){
			this._defaultMove();
		}else{
			this._setMove(index);
			this.onShow(this._index);
			this._targetMove();
		}
	},
	
	destroy: function(){
		clearTimeout(this._timerDelay);
		clearTimeout(this._timerMove);
		
		$$OBEA.selfe.fireEvent(this, 'destroy');
		
		var pos = this._pos;
		this._each(function(o){
			var style = o.node.style;
			style[pos] = o.style;
			style.zIndex = o.zIndex;
			style.position = o.position;
			$$OBEA.helpe.removeEvent(o.node, 'mouseenter', o.SHOW);
			o.SHOW = o.node = null;
		});
		$$OBEA.helpe.removeEvent(this._container, 'mouseleave', this._LEAVE);
		$$OBEA.setStyle(this._container, this._style);
		
		this._container = this._nodes = this._MOVE = this._LEAVE = null;
		$$OBEA.selfe.clearEvent(this);
	}
};	

muBM.prototype._init = (function(){
	var init = muBM.prototype._init,
		reset = muBM.prototype.reset,
		methods = {
			'init' : function(){
				this.autoDelay = this.options.autoDelay | 0;
				
				this._autoTimer = null;
				this._autoPause = false;
				
				this._NEXT = $$OBEA.bind(function(){
					this.show(this._index + 1);
				}, this);
			},
			'leave' : function(){
				this.autoClose = this._autoPause = false;
				this._autoNext();
			},
			'enter' : function(){
				clearTimeout(this._autoTimer);
				this._autoPause = true;
			},
			'finish' : function(){
				this._autoNext();
			},
			'destroy' : function(){
				clearTimeout(this._autoTimer);
			}
		},
		prototype = {
			_autoNext : function(){
				if(!this._autoPause){
					clearTimeout(this._autoTimer);
					this._autoTimer = setTimeout(this._NEXT, this.autoDelay);
				}
			},
			reset : function(index){
				reset.call(this, index == undefined ? this._index : index);
				this._autoNext();
			}
		};
	
	return function(){
		var options = arguments[0][1];
		if(options && options.auto){
			$$OBEA.extend(options, {
				autoDelay : 2000
			}, false);
			
			$$OBEA.extend(this, prototype);
			
			$$OBEA.forEach(methods, function(method, name){
				$$OBEA.selfe.addEvent(this, name, method);
			}, this);
		}
		init.apply(this, Array.prototype.slice.apply(arguments));
	}
})();

muBM.prototype._init = (function(){
	var init = muBM.prototype._init,
		methods = {
			'init' : function(){
				this._tipPos = /^(bottom|top|right|left)$/.test(this.options.tipPos.toLowerCase()) ? RegExp.$1 : 'bottom';
			},
			'initNodes' : function(){
				var opt = this.options,
					tipTag = opt.tipTag,
					tipClass = opt.tipClass,
					re = tipClass && new RegExp('(^|\\s)' + tipClass + '(\\s|$)'),
					getTipNode = function(node){
						var nodes = node.getElementsByTagName(tipTag);
						if(tipClass){
							nodes = $$OBEA.filter(nodes, function(n){
								return re.test(n.className);
							});
						}
						return nodes[0];
					};
					
				var tipShow = opt.tipShow,
					tipClose = opt.tipClose,
					offset = /right|left/.test(this._tipPos) ? 'offsetWidth' : 'offsetHeight';
				
				this._each(function(o){
					var node = o.node,
						tipNode = getTipNode(node);
					
					node.style.overflow = 'hidden';
					tipNode.style.position = 'absolute';
					
					o.tip = {
						'node' : tipNode,
						'show' : tipShow != undefined ? tipShow : 0,
						'close' : tipClose != undefined ? tipClose : -tipNode[offset]
					};
				});			
			},
			'setMove' : function(index){
				var maxIndex = this._nodes.length - 1;
				this._each(function(o, i){
					var tip = o.tip;
					if(this._reverse){
						i = maxIndex - i;
					}
					tip.target = index == undefined || index != i ? tip.close : tip.show;
					tip.begin = tip.current;
					tip.change = tip.target - tip.begin;
				});
			},
			'tweenMove' : function(){
				this._setTipPos(function(tip){
					return this.tween(this._time, tip.begin, tip.change,this.duration);
				});
			},
			'targetMove' : function(){
				this._setTipPos(function(tip){
					return tip.target;
				});
			},
			'defaultMove' : function(){
				this._setTipPos(function(tip){
					return tip.close;
				});
			},
			'destroy' : function(){
				this._each(function(o){
					o.tip = null;
				});
			}
		},
		prototype = {
			_setTipPos : function(method){
				var pos = this._tipPos;
				this._each(function(o, i){
					var tip = o.tip;
					tip.node.style[pos] = (tip.current = Math.round(method.call(this, tip))) + 'px';
				});
			}
		};
return function(){
	var options = arguments[0][1];
	if(options && options.tip == true){
		$$OBEA.extend(options, {
			tipPos : 'bottom',
			tipTag : '*',
			tipClass : '',
			tipShow : null,
			tipClose : null
		}, false);
		
		$$OBEA.extend(this, prototype);
		
		$$OBEA.forEach(methods, function(method, name){
			$$OBEA.selfe.addEvent(this, name, method);
		}, this);
	}
	init.apply(this, arguments);
}
})();


window.mooluBM = mooluBM;
window.muBM = muBM;

})(window)